package usersManagement.model;

import org.codehaus.jackson.annotate.JsonIgnore;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotEmpty;
import org.jboss.resteasy.annotations.LinkHeaderParam;

import javax.persistence.*;
import javax.validation.constraints.Digits;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import javax.xml.bind.annotation.XmlRootElement;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;

@Entity
@XmlRootElement // serialize object as XML or JSON object depending on the mime type (text/xml or application/json)
@Table(name = "users", uniqueConstraints = @UniqueConstraint(columnNames = "username"))
public class User implements Serializable {
// ------------------------------ FIELDS ------------------------------

    private static final long serialVersionUID = -5317081278196057038L;
    /*
        @Fetch(FetchMode.JOIN) only works if we are retrieving the object with find() method of EM, not with JPQL/Criteria
        if you use name queries you MUST user "left join fetch" on the relation to do the join
         BTW : @Fetch is Hibernate specific and not part of JPA so you need to import hibernate-core
     */

    @NotEmpty
    @ElementCollection(fetch=FetchType.EAGER)
    @CollectionTable(name = "roles", joinColumns=@JoinColumn(name="USER_ID"))
    @Column(name="role")
    protected Set<String> roles;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @NotEmpty
    @Pattern(regexp = "[A-Za-z ]*", message = "must contain only letters and spaces")
    private String firstName;

    @NotEmpty
    @Pattern(regexp = "[A-Za-z ]*", message = "must contain only letters and spaces")
    private String lastName;

    @NotNull
    @NotEmpty
    @Email
    private String email;

    @NotNull
    @Size(min = 10, max = 12)
    @Digits(fraction = 0, integer = 12)
    @Column(name = "phone_number")
    private String phoneNumber;

    @NotNull
    @Size(min = 3, max = 25)
    @Pattern(regexp = "[A-Za-z0-9]*", message = "must contain only letters and numbers")
    @Column(name = "username",unique = true)
    private String username;

    @NotNull
    @Size(min = 3, max = 25)
    @Pattern(regexp = "[A-Za-z0-9]*", message = "must contain only letters and numbers")
    private String password;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name="ORGANIZATION_ID")
    private Organization organization ;

// --------------------------- CONSTRUCTORS ---------------------------

    public User() {
        id = null ;
        roles = new HashSet<String>() ;
    }

    public User(String firstName, String lastName,
			String email, String phoneNumber, String username, String password, Set<String> roles) {
		this.firstName = firstName;
		this.lastName = lastName;
		this.email = email;
		this.phoneNumber = phoneNumber;
		this.username = username;
		this.password = password;
		this.roles = roles;
    }

// -------------------------- OTHER METHODS --------------------------


    @JsonIgnore
	public String getFullName() {
        return firstName + " " + lastName;
    }

    @JsonIgnore
    public String getRolesAsString() {
        if ( roles.size() == 0 ) {
            return "" ;
        }

        StringBuilder sb = new StringBuilder() ;
        for ( String s : roles )
            sb.append(s).append('|') ;

        return sb.substring(0,sb.length()-1).toString() ;
    }

// --------------------- GETTER / SETTER METHODS ---------------------

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    @JsonIgnore
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public Organization getOrganization() {
        return organization;
    }

    public void setOrganization(Organization organization) {
        this.organization = organization;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getPhoneNumber() {
        return phoneNumber;
    }

    public void setPhoneNumber(String phoneNumber) {
        this.phoneNumber = phoneNumber;
    }

    public Set<String> getRoles() {
        return roles;
    }

    public void setRoles(Set<String> roles) {
        this.roles = roles;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

// ------------------------ CANONICAL METHODS ------------------------

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        User user = (User) o;

        if (!username.equals(user.username)) return false;

        return true;
    }

    @Override
    public int hashCode() {
        return username.hashCode();
    }

	@Override
	public String toString() {
		return "User [roles=" + roles + ", id=" + id + ", firstName="
				+ firstName + ", lastName=" + lastName + ", email=" + email
				+ ", phoneNumber=" + phoneNumber + ", username=" + username
				+ ", password=" + password + "]";
	}
}